package com.xuecheng.media.service.jobhandler;

import com.xuecheng.base.utils.Mp4VideoUtil;
import com.xuecheng.media.model.po.MediaProcess;
import com.xuecheng.media.service.MediaFileProcessService;
import com.xuecheng.media.service.MediaFileService;
import com.xxl.job.core.context.XxlJobHelper;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.io.File;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
 * @Author:王亚栋
 * @Date:2023/7/29 20:20
 * @Version:1.0
 */
@Component
@Slf4j(topic = "视频处理任务")
public class  VideoTask {

    @Autowired
    private MediaFileProcessService mediaFileProcessService;

    @Autowired
    private MediaFileService mediaFileService;

    @Value("${videoprocess.ffmpegpath}")
    private String ffmPegPath;

    @XxlJob("videoJobHandler")
    public void shardingJobHandler() throws Exception {

        System.out.println("处理分片广播...");

        int shardIndex = XxlJobHelper.getShardIndex(); //执行器的序号，从0开启
        int shardTotal = XxlJobHelper.getShardTotal(); // 执行器总数

        log.info("shardIndex={},shardTotal={}",shardIndex,shardTotal);

        //确定CPU的核心数
        int processors = Runtime.getRuntime().availableProcessors();
        log.info("CPU的核心数:{}",processors);

        //查询待处理任务
        List<MediaProcess> mediaProcessList = mediaFileProcessService.getMediaProcessList(shardIndex, shardTotal, processors);
        log.info("待处理任务列表:{}",mediaProcessList);

        //任务数量
        int size = mediaProcessList.size();
        log.info("取到视频处理任务数:{}",size);
        if (size <= 0){
            return;
        }

        //创建一个线程池
        ExecutorService executorService = Executors.newFixedThreadPool(size);

        // 使用计数器
        CountDownLatch countDownLatch = new CountDownLatch(size);
        mediaProcessList.forEach( mediaProcess -> {

            log.info("拿到的mediaProcess为:{}",mediaProcess);

            //合理开启任务(锁)
            //将任务加入线程池
            executorService.execute(()->{

                try {

                    //任务执行逻辑

                    //任务id
                    Long taskId = mediaProcess.getId();
                    //文件id就是md5
                    String fileId = mediaProcess.getFileId();
                    //开启任务
                    boolean b = mediaFileProcessService.startTak(taskId);

                    if (!b) {
                        log.error("抢占任务失败！任务id:{}", taskId);

                        return;
                    }

                    String bucket = mediaProcess.getBucket();
                    log.info("待处理任务列表的taskId:{},mediaProcess的bucket名:{}",taskId,bucket);

                    String objectName = mediaProcess.getFilePath();
                    log.info("待处理任务列表的taskId:{},mediaProcess的objectName名:{}",taskId,objectName);

                    //下载minio视频到本地
                    File file = mediaFileService.downloadFileFromMinio(bucket, objectName);
                    log.info("下载minio视频到本地的文件为:{}",file);

                    if (file == null) {

                        log.error("下载文件失败！任务id:{},桶:{},ObjectName:{}", taskId, bucket, objectName);

                        //保存任务处理失败的结果
                        mediaFileProcessService.saveProcessFinishStatus(taskId, "3", fileId, null, "下载视频到本地失败！");
                        return;
                    }


                    //执行视频转码

                    //原avi视频的路径
                    String video_path = file.getAbsolutePath();
                    log.info("原avi视频的路径:{}",video_path);

                    //转换后mp4文件的名称
                    String mp4_name = fileId + ".mp4";

                    //先创建一个临时文件,作为转换后的文件
                    File mp4_tempFile = null;
                    try {

                        mp4_tempFile = File.createTempFile("minio", ".mp4");
                        log.info("临时文件为:{}",mp4_tempFile);

                    } catch (Exception e) {
                        log.error("创建临时文件出现异常！{}", e.getMessage());
                        //保存任务处理失败的结果
                        mediaFileProcessService.saveProcessFinishStatus(taskId, "3", fileId, null, "创建临时文件失败！");
                        e.printStackTrace();
                    }

                    //转换后mp4文件的路径
                    String mp4_path = mp4_tempFile.getAbsolutePath();
                    log.info("转码后mp4文件的路径:{}", mp4_path);
                    //创建工具类对象
                    /**
                     * ffmPegPath Ffmpeg工具路径
                     * video_path  原视频路径
                     * mp4_name    转换后mp4文件的名称
                     * mp4_path    转码后mp4文件的路径
                     */
                    Mp4VideoUtil videoUtil = new Mp4VideoUtil(ffmPegPath, video_path, mp4_name, mp4_path);
                    //开始视频转换，成功将返回success
                    String reult = videoUtil.generateMp4();

                    if (!reult.equals("success")) {

                        log.error("视频转码失败！原因:{},bucket:{},objectName:{}", reult, bucket, objectName);

                        //保存任务处理失败的结果
                        mediaFileProcessService.saveProcessFinishStatus(taskId, "3", fileId, null, reult);
                        return;
                    }

                    //TODO 将avi视频转码成mp4文件上传到Minio
                    boolean b1 = mediaFileService.addMediaTypeToMinio2(mp4_path, "video/mp4", bucket, objectName);

                    if (!b1) {

                        log.error("上传mp4到minio失败了,taskId:{}", taskId);

                        mediaFileProcessService.saveProcessFinishStatus(taskId, "3", fileId, null, "上传mp4文件到minio失败！");
                        return;
                    }

                    // mp4文件的url
                    String url = getFilePath(fileId, ".mp4");
                    log.info("得到上传到minio中的mp4文件的路径:{} ==>", url);

                    //保存任务处理结果 更新任务状态为成功
                    mediaFileProcessService.saveProcessFinishStatus(taskId, "2", fileId, url, "文件转码成功！");
                }finally {

                    //计数器-1
                    countDownLatch.countDown();
                }


            });
        });

        //直到减为0阻塞结束
        //阻塞 指定一个最大限度的等待时间
        countDownLatch.await(30, TimeUnit.MINUTES);



    }

    /**
     * 得到文件路径
     * @param fileMd5 文件Md5值
     * @param fileExt  扩展名
     * @return
     */
    private String getFilePath(String fileMd5,
                               String fileExt){

        return fileMd5.substring(0,1) + "/" + fileMd5.substring(1,2) + "/" + fileMd5 + "/" + fileMd5 + fileExt;
    }

}
